package pl.edu.pw.mini.java2.Communicator.Client;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import javax.sound.sampled.*;
import javax.swing.JOptionPane;

public class SoundPlayer {
	BlockingQueue<byte[]> buffer = new LinkedBlockingDeque<byte[]>();
	volatile boolean playing = false;
	private static SoundPlayer instance;

	public static synchronized SoundPlayer getInstance() {
		if (instance == null)
			instance = new SoundPlayer();
		return instance;
	}

	Thread t = new Thread(new Runnable() {
		@Override
		public void run() {
			playFromBuffer();
		}
	});

	public synchronized void setPlaying() {
		playing = true;
	}

	public synchronized boolean isPlaying() {
		return playing;
	}

	public synchronized void stopPlaying() {
		playing = false;
	}

	public void playSample(byte[] sample) {
		buffer.add(sample);
		if (isPlaying())
			return;
		setPlaying();
		t.start();
	}

	void playFromBuffer() {
		setPlaying();
		AudioFormat format = getFormat();
		DataLine.Info sourceInfo;
		SourceDataLine sourceLine;
		sourceInfo = new DataLine.Info(SourceDataLine.class, format);
		try {
			sourceLine = (SourceDataLine) AudioSystem.getLine(sourceInfo);
			sourceLine.open(format);
			sourceLine.start();
		} catch (LineUnavailableException e) {
			JOptionPane.showConfirmDialog(null, "Cannot open sound card for play.");
			return;
		}
		try {
			while (isPlaying()) {
				byte sample[];
				sample = buffer.take();
				if (sample.length == 0)
					break;
				sourceLine.write(sample, 0, sample.length);
			}
		} catch (InterruptedException e) {
			// End playing
			sourceLine.drain();
			sourceLine.close();
		}
	}

	public void playMessage(Message message) {
		playSample(message.getMessage());
	}

	public static AudioFormat getFormat() {
		float sampleRate = 8000;
		int sampleSizeInBits = 8;
		int channels = 1;
		boolean signed = true;
		boolean bigEndian = true;
		return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,
				bigEndian);
	}
}
